//
//  SFExpandableTableViewCell.m
//  TableViewFramework
//
//  Created by 支晓辉 on 16/3/30.
//  Copyright © 2016年 wishselfly. All rights reserved.
//

#import "SFExpandableTableViewCell.h"
#import "SFGroupItem.h"

/** 是否适用约束动画 */
#define ANIMATE_WITH_CONSTRAINTS
/** 动画持续的时间 */
#define ANIMATE_DURATION 0.3f

const CGFloat kSepLineHeight = 1.f;

@interface SFExpandableTableViewCell ()
/** 主视图 */
@property (weak, nonatomic) IBOutlet UIView *view;
/** 是否展开的图片视图 */
@property (weak, nonatomic) IBOutlet UIImageView *expandedImageView;
/** 标题标签 */
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
/** 标题占位视图 */
@property (weak,nonatomic) IBOutlet UIView *titleSpanView;
/** 存放内容的视图 */
@property (weak, nonatomic) IBOutlet UIView *bodyView;

/** 每一行的视图集合 */
@property (strong, nonatomic) NSMutableArray<MOVABLE_VIEW*> *rowViews;
/** 分割线视图的集合 */
@property (strong, nonatomic) NSMutableArray<UIView*> *sepLineViews;
/** 同步用 */
@property (strong, nonatomic) NSLock *locker;
/** 当前高亮的分割线 */
@property (weak, nonatomic) UIView *curHighLightedSepLine;
/** 当前视图对应的tableView */
@property (weak, nonatomic) UITableView *tableView;

@end

@implementation SFExpandableTableViewCell
{
    BOOL isInitGesture;     //!< 是否已经初始化手势
    BOOL isAnimate;         //!< 是否正在动画中
}
@synthesize groupData           = _groupData;

- (instancetype)init {
    if (self = [super init]) {
        [self _initSubView];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self _initSubView];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self _initSubView];
    }
    return self;
}

#pragma mark - Override

- (void)initLongPressGesture:(UILongPressGestureRecognizer *)gesture {
    if (isInitGesture) {
        return;
    }
    if (!self.titleSpanView) {
        return;
    }
    isInitGesture = YES;
    gesture.minimumPressDuration = 0.5f;
    [self.titleSpanView addGestureRecognizer:gesture];
    self.titleSpanView.userInteractionEnabled = YES;
    
    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTitleSpanView:)];
    tapGesture.numberOfTouchesRequired = 1;
    [self.titleSpanView addGestureRecognizer:tapGesture];
}

#pragma mark - Public methods

#pragma mark Movable control

- (void)insertDataAt:(NSInteger)index data:(SFGroupItem*)item animated:(BOOL)animated complete:(void (^)())completeBlock {
    
    MOVABLE_VIEW *v = [self createMovableViewWithData:item index:index];
    UIView *sepLine    = [self createSepLineViewWithIndex:index];
    v.item = item;
    
    if (index >= self.groupData.childData.count) {
        [self.groupData.childData addObject:item];
        [self.rowViews addObject:v];
        [self.sepLineViews addObject:sepLine];
    } else {
        [self.groupData.childData insertObject:item  atIndex:index];
        [self.rowViews insertObject:v atIndex:index];
        [self.sepLineViews insertObject:sepLine atIndex:index];
    }
    
#ifdef ANIMATE_WITH_CONSTRAINTS
    if (animated) { //执行动画显示
        isAnimate = YES;
        v.alpha       = 0.f;
        sepLine.alpha = 0.f;
    }
    [self.bodyView addSubview:v];
    [self.bodyView addSubview:sepLine];
    [UIView animateWithDuration:animated ? ANIMATE_DURATION:0.f animations:^{
        v.alpha = 1.f;
        sepLine.alpha = 1.f;
        [self updateConstraintsForMovableView];
        [self.bodyView layoutIfNeeded];
    } completion:^(BOOL finished) {
        isAnimate = NO;
        if (completeBlock) {
            completeBlock();
        }
    }];
#else
    if (animated) { //执行动画显示
        isAnimate = YES;
        v.alpha       = 0.f;
        sepLine.alpha = 0.f;
        [self.bodyView addSubview:v];
        [self.bodyView addSubview:sepLine];
        [self updateChildrenLayoutWithAnimation:YES otherAnimation:^{
            v.alpha       = 1.f;
            sepLine.alpha = 1.f;
        } complete:^(BOOL finish) {
            [self updateConstraintsForMovableView];
            isAnimate = NO;
        }];
    } else {    //直接显示
        [self.bodyView addSubview:v];
        [self.bodyView addSubview:sepLine];
        [self updateChildrenLayoutWithAnimation:NO];
        [self updateConstraintsForMovableView];
    }
#endif
}

- (void)moveDataFrom:(NSInteger)srcIndex to:(NSInteger)destIndex animated:(BOOL)animated complete:(void (^)())completeBlock {
    if (srcIndex < 0 || srcIndex >= self.groupData.childData.count ||
        destIndex < 0 || destIndex >= self.groupData.childData.count ||
        srcIndex == destIndex) {
        return;
    }
    
    SFGroupItem *srcItem = self.groupData.childData[srcIndex];
    MOVABLE_VIEW *srcMovableView = self.rowViews[srcIndex];
    UIView *srcSepLine = self.sepLineViews[srcIndex];
    
    [self.rowViews removeObjectAtIndex:srcIndex];
    [self.sepLineViews removeObjectAtIndex:srcIndex];
    
    [self.rowViews insertObject:srcMovableView atIndex:destIndex];
    [self.sepLineViews insertObject:srcSepLine atIndex:destIndex];
    
    isAnimate = animated;
    [self.groupData.childData removeObjectAtIndex:srcIndex];
    [self.groupData.childData insertObject:srcItem atIndex:destIndex];
#ifdef ANIMATE_WITH_CONSTRAINTS
    [UIView animateWithDuration:animated ? ANIMATE_DURATION:0.f animations:^{
        [self updateConstraintsForMovableView];
        [self.bodyView layoutIfNeeded];
    } completion:^(BOOL finished) {
        isAnimate = NO;
        if (completeBlock) {
            completeBlock();
        }
    }];
#else
    [self updateChildrenLayoutWithAnimation:animated otherAnimation:nil complete:^(BOOL finished) {
        if (finished) {
            [self.groupData.childData removeObjectAtIndex:srcIndex];
            [self.groupData.childData insertObject:srcItem atIndex:destIndex];
            [self updateConstraintsForMovableView];
            isAnimate = NO;
        }
    }];
#endif
}

- (void)deleteDataAt:(NSInteger)index animated:(BOOL)animated {
    if (index < 0 || index >= self.groupData.childData.count) {
        return;
    }
    
    MOVABLE_VIEW *movableView = self.rowViews[index];
    UIView *prevSepLine = index - 1 >= 0 ? self.sepLineViews[index - 1]:nil;
    UIView *sepLine = self.sepLineViews[index];

    //删除对应的数据
    [self.rowViews removeObjectAtIndex:index];
    [self.sepLineViews removeObjectAtIndex:index];
    
    isAnimate = animated;
    
    [self.groupData.childData removeObjectAtIndex:index];
    
#ifdef ANIMATE_WITH_CONSTRAINTS
    [UIView animateWithDuration:animated ? ANIMATE_DURATION:0.f animations:^{
        movableView.alpha = 0.f;
        sepLine.alpha = 0.f;
        [self updateConstraintsForMovableView];
        
        if (prevSepLine) {
            [self.bodyView addConstraints:[NSLayoutConstraint
                                           constraintsWithVisualFormat:@"V:[prevSepLine]-0-[movableView]"
                                           options:0
                                           metrics:nil
                                           views:NSDictionaryOfVariableBindings(movableView, prevSepLine)]];
        }else {
            [self.bodyView addConstraints:[NSLayoutConstraint
                                           constraintsWithVisualFormat:@"V:|-0-[movableView]"
                                           options:0
                                           metrics:nil
                                           views:NSDictionaryOfVariableBindings(movableView)]];
        }
        
        [self.bodyView layoutIfNeeded];
    } completion:^(BOOL finished) {
        if (!movableView.isMoving) {
            [movableView removeFromSuperview];
        } else {
            movableView.hidden = YES;
        }
        [sepLine removeFromSuperview];
        isAnimate = NO;
    }];
#else
    if (animated) {
        [self updateChildrenLayoutWithAnimation:YES otherAnimation:^{
            movableView.alpha = 0.f;
            sepLine.alpha = 0.f;
        } complete:^(BOOL finished) {
            [movableView removeFromSuperview];
            [sepLine removeFromSuperview];
            [_groupData.childData removeObjectAtIndex:index];
            [self updateConstraintsForMovableView];
            isAnimate = NO;
        }];
    } else {
        [movableView removeFromSuperview];
        [sepLine removeFromSuperview];
        [_groupData.childData removeObjectAtIndex:index];
        [self updateChildrenLayoutWithAnimation:NO];
        [self updateConstraintsForMovableView];
    }
#endif
}

- (void)updateChildrenLayoutWithAnimation:(BOOL)animated {
    [self updateChildrenLayoutWithAnimation:animated otherAnimation:nil complete:nil];
}

- (void)updateChildrenLayoutWithAnimation:(BOOL)animated otherAnimation:(void (^)())otherAnimation complete:(void (^)(BOOL finished))completeBlock {
    void (^layoutBlock)() = ^{
        for (NSInteger i = 0; i < self.rowViews.count; i++) {
            if (i >= self.rowViews.count || i >= self.sepLineViews.count) {
                return;
            }
            MOVABLE_VIEW *movableView = self.rowViews[i];
            CGRect r = movableView.frame;
            r.origin.y = i * ([movableView.class rowHeight] + kSepLineHeight);
            movableView.frame = r;
            
            UIView *sepLine = self.sepLineViews[i];
            r = sepLine.frame;
            r.origin.y = i * [movableView.class rowHeight] + kSepLineHeight * (i - 1);
            sepLine.frame = r;
        }
        if (otherAnimation) {
            otherAnimation();
        }
    };
    if (animated) {
        [UIView animateWithDuration:0.5f animations:layoutBlock completion:completeBlock];
    } else {
        layoutBlock();
        completeBlock(YES);
    }
}

#pragma mark Check intersection rect

- (NSInteger)intersectMovableViewRectWith:(CGRect)screenRect filterItem:(SFGroupItem*)item {
    for (NSInteger i = self.rowViews.count - 1; i >= 0; i--) {
        MOVABLE_VIEW *v = self.rowViews[i];
        if (v.item == item) {
            continue;
        }
        CGRect targetRect = [self.bodyView convertRect:v.frame toView:[UIApplication sharedApplication].keyWindow];
        CGRect topRect = CGRectMake(
                                    CGRectGetMinX(targetRect),
                                    CGRectGetMinY(targetRect),
                                    CGRectGetWidth(targetRect),
                                    CGRectGetHeight(targetRect) / 2.f
                                    );
        CGRect bottomRect = CGRectMake(
                                       CGRectGetMinX(targetRect),
                                       CGRectGetMidY(targetRect),
                                       CGRectGetWidth(targetRect),
                                       CGRectGetHeight(targetRect) / 2.f
                                       );
        /** 跟上半边相交且用户拖动的矩形的Y坐标比当前项的Y坐标大 */
        BOOL topIntersect = CGRectIntersectsRect(screenRect, topRect) &&
                            CGRectGetMinY(screenRect) > CGRectGetMinY(topRect);
        /** 跟上半边相交且用户拖动的矩形的Y坐标比当前项的Y坐标小 */
        BOOL topIntersectYNotGreaterThanTarget = CGRectIntersectsRect(screenRect, topRect) &&
                                             CGRectGetMinY(screenRect) <= CGRectGetMinY(topRect);
        /** 跟下半边相交且用户拖动的矩形的Y坐标比当前项的Y坐标大 */
        BOOL bottomIntersect = CGRectIntersectsRect(screenRect, bottomRect) &&
                               CGRectGetMinY(screenRect) > CGRectGetMinY(bottomRect);
        
        if (topIntersect || topIntersectYNotGreaterThanTarget || bottomIntersect) {
            //以下两项判断主要用于跨组移动的时候
            if ((topIntersectYNotGreaterThanTarget && i != 0) ||        //如果与上半边相交但是不是组的第一个项
                (bottomIntersect && i != self.rowViews.count - 1) ) {   //如果与下半边相交但是不是组的最后一项
                continue;
            }
            NSInteger resIndex = -1;
                resIndex = i;
            
            UIView *sepLine = self.sepLineViews[resIndex];
            //如果是当前分割线则
            if (sepLine != self.curHighLightedSepLine && self.curHighLightedSepLine) {
                [self unHighLightedSepLine:self.curHighLightedSepLine];
                self.curHighLightedSepLine = sepLine;
                [self highLightedSepLine:self.curHighLightedSepLine];
            }
            return resIndex;
        }
    }
    return -1;
}

- (MOVABLE_VIEW *)getMovableViewByPoint:(CGPoint)pt {
    for (MOVABLE_VIEW *v in self.rowViews) {
        CGRect screenRect = [self.bodyView convertRect:v.frame toView:[UIApplication sharedApplication].keyWindow];
        if (CGRectContainsPoint(screenRect, pt)) {
            return v;
        }
    }
    return nil;
}

- (void)endHighLight {
    if (self.curHighLightedSepLine) {
        [self unHighLightedSepLine:self.curHighLightedSepLine];
        self.curHighLightedSepLine = nil;
    }
}

#pragma mark Get row view

- (MOVABLE_VIEW *)movableViewAtIndex:(NSInteger)index {
    if (index < self.rowViews.count) {
        return self.rowViews[index];
    }
    return nil;
}

#pragma mark Static methods

+ (CGFloat)calcRowHeightWithGroup:(SFGroup*)group {
    CGFloat res = group.childData.count;
    if (!group.expanded) {
        res = 0;
    }
    CGFloat height = res * [MOVABLE_VIEW rowHeight] + res * kSepLineHeight + 46.f;
    //结尾的45为标题栏的高度35再加上底部外边距的10
    return height;
}

#pragma mark - Private methods

/**
 *  初始化子视图
 */
- (void)_initSubView {
    self.contentView.layer.cornerRadius = 5.f;
    self.contentView.layer.borderColor = [UIColor blackColor].CGColor;
    self.contentView.layer.borderWidth = 0.2f;
    
    self.selectionStyle = UITableViewCellSelectionStyleNone;
}

/**
 *  更新每行的子视图
 */
- (void)updateChildren {
    [self.locker lock];
    //清空视图
    for (UIView *v in self.bodyView.subviews) {
        [v removeFromSuperview];
    }
    [self.rowViews removeAllObjects];
    [self.sepLineViews removeAllObjects];
    
    NSInteger index = 0;
    for (SFGroupItem *i in self.groupData.childData) {
        MOVABLE_VIEW *movableView = [self createMovableViewWithData:i index:index];
        [self.rowViews addObject:movableView];
        
        UIView *sepLine = [self createSepLineViewWithIndex:index];
        [self.sepLineViews addObject:sepLine];
        [self.bodyView addSubview:movableView];
        [self.bodyView addSubview:sepLine];
        
        index++;
    }
    [self updateConstraintsForMovableView];
    [self.locker unlock];
}

/**
 *  更新所有子视图的约束
 */
- (void)updateConstraintsForMovableView {
    [self removeAllConstraintsForMovableView];
    
    for (NSInteger i = self.groupData.childData.count - 1; i >= 0; i--) {
        if (i >= self.rowViews.count || i>= self.sepLineViews.count) {
            continue;
        }
        MOVABLE_VIEW *movableView = self.rowViews[i];
        UIView *sepLineView       = self.sepLineViews[i];
        movableView.translatesAutoresizingMaskIntoConstraints = NO;
        sepLineView.translatesAutoresizingMaskIntoConstraints = NO;
        
        for (UIView *v in movableView.subviews) {   //防止子视图的AutoLayout失效
            v.translatesAutoresizingMaskIntoConstraints = YES;
        }
        
        [self.bodyView addConstraints:
         [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[sepLineView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(sepLineView)]];
        
        if (i == 0) {
            [self.bodyView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[movableView]-0-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(movableView)]];
            [self.bodyView addConstraints:
             [NSLayoutConstraint
              constraintsWithVisualFormat:@"V:|-0-[movableView(height)]-0-[sepLineView(lineHeight)]"
                                  options:0
                                  metrics:@{
                                            @"height":@([MOVABLE_VIEW rowHeight]),
                                            @"lineHeight":@(kSepLineHeight)
                                            }
                                    views:NSDictionaryOfVariableBindings(movableView, sepLineView)]];
        } else {
            UIView *prevSepLineView = self.sepLineViews[i - 1];
            [self.bodyView addConstraints:
             [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[movableView]-0-|"
                                                     options:0
                                                     metrics:nil
                                                       views:NSDictionaryOfVariableBindings(movableView)]];
            [self.bodyView addConstraints:
             [NSLayoutConstraint
              constraintsWithVisualFormat:@"V:[prevSepLineView]-0-[movableView(height)]-0-[sepLineView(lineHeight)]"
                                  options:0
                                  metrics:@{
                                            @"height":@([MOVABLE_VIEW rowHeight]),
                                            @"lineHeight":@(kSepLineHeight)
                                            }
                                  views:NSDictionaryOfVariableBindings(
                                                                       movableView,
                                                                       sepLineView,
                                                                       prevSepLineView
                                                                       )
              ]
             ];
        }
    }
}

/**
 *  移除所有子视图的约束
 */
- (void)removeAllConstraintsForMovableView {
    for (MOVABLE_VIEW *v in self.rowViews) {
        [v removeConstraints:v.constraints];
    }
    for (UIView *v in self.sepLineViews) {
        [v removeConstraints:v.constraints];
    }
    NSMutableArray *removeConstrains = [NSMutableArray array];
    for (NSLayoutConstraint *c in self.bodyView.constraints) {
        if ([self.rowViews containsObject:c.firstItem] || [self.rowViews containsObject:c.secondItem] ||
            [self.sepLineViews containsObject:c.firstItem] || [self.sepLineViews containsObject:c.secondItem]) {
            [removeConstrains addObject:c];
        }
    }
    [self.bodyView removeConstraints:removeConstrains];
}

/**
 *  创建可移动的视图
 *
 *  @param i     对应的数据模型
 *  @param index 视图哦所在的索引
 *
 */
- (MOVABLE_VIEW*)createMovableViewWithData:(SFGroupItem*)i index:(NSInteger)index {
    MOVABLE_VIEW *v = (MOVABLE_VIEW*)[[UINib nibWithNibName:NSStringFromClass([MOVABLE_VIEW class]) bundle:nil] instantiateWithOwner:nil options:nil].firstObject;
    v.title  = i.title;
    v.parent = self.groupData;
    v.item   = i;
    
    [self.bodyView addSubview:v];
    v.frame = CGRectMake(
                         0,
                         index * [MOVABLE_VIEW rowHeight] + kSepLineHeight * index,
                         CGRectGetWidth(self.bodyView.frame),
                         [MOVABLE_VIEW rowHeight]
                         );
    return v;
}

/**
 *  生成分割线视图
 */
- (UIView*)createSepLineViewWithIndex:(NSInteger)index {
    UIView *sepLineView = [[UIView alloc] init];
    sepLineView.backgroundColor = [UIColor lightGrayColor];
    
    sepLineView.frame = CGRectMake(
                                   0,
                                   index * [MOVABLE_VIEW rowHeight] + [MOVABLE_VIEW rowHeight] + kSepLineHeight * index,
                                   CGRectGetWidth(self.bodyView.frame),
                                   kSepLineHeight
                                   );
    
    return sepLineView;
}

#pragma mark View control

/**
 *  高亮某条分割线
 *
 *  @param sepLine 分割线对应的视图
 */
- (void)highLightedSepLine:(UIView*)sepLine {
    sepLine.backgroundColor = [UIColor blueColor];
    sepLine.layer.borderColor = [UIColor blueColor].CGColor;
    sepLine.layer.borderWidth = 5.f;
}

/**
 *  取消某条分割线的高亮状态
 *
 *  @param sepLine 对应的分割线的视图
 */
- (void)unHighLightedSepLine:(UIView*)sepLine {
    sepLine.backgroundColor = [UIColor lightGrayColor];
    sepLine.layer.borderWidth = 0.f;
}

#pragma mark Gesture

/**
 *  标题空白视图被单击的时候
 *
 *  @param g 对应的单击手势识别器
 */
- (void)tapTitleSpanView:(UITapGestureRecognizer*)g {
    [self.tableView beginUpdates];
    self.groupData.expanded = !self.groupData.expanded;
    
    [UIView animateWithDuration:0.2f animations:^{
        self.bodyView.alpha = self.groupData.expanded ? 1.f:0.f;
        self.expandedImageView.layer.transform = self.groupData.expanded ?
        CATransform3DRotate(CATransform3DIdentity, M_PI_2, 0, 0, -1.f):
        CATransform3DIdentity;
    }];
    
    [self.tableView endUpdates];
}

#pragma mark - Setters

- (void)setTitle:(NSString *)title {
    self.titleLabel.text = title;
}

- (void)setGroupData:(SFGroup *)groupData {
    _groupData = groupData;
    
    self.expandedImageView.layer.transform = groupData.expanded ?
    CATransform3DRotate(CATransform3DIdentity, M_PI_2, 0, 0, -1.f):
    CATransform3DIdentity;
    self.bodyView.alpha = groupData.expanded ? 1.f:0.f;
    [self updateChildren];
}

#pragma mark - Getters

- (NSString *)title {
    return self.titleLabel.text;
}

- (SFGroup *)groupData {
    return _groupData;
}

- (NSMutableArray<UIView *> *)sepLineViews {
    if (!_sepLineViews) {
        _sepLineViews = [NSMutableArray array];
    }
    return _sepLineViews;
}

- (NSMutableArray<MOVABLE_VIEW *> *)rowViews {
    if (!_rowViews) {
        _rowViews = [NSMutableArray array];
    }
    return _rowViews;
}

- (NSLock *)locker {
    if (!_locker) {
        _locker = [[NSLock alloc] init];
    }
    return _locker;
}

- (UITableView *)tableView {
    if (!_tableView) {
        UIView *v = self;
        while (![v isKindOfClass:[UITableView class]] && v) {
            v = v.superview;
        }
        
        _tableView = (UITableView*)v;
    }
    return _tableView;
}

@end
